κ²¬κ³ νκ³ μ μ§λ³΄μ κ°λ₯ν μ ν리μΌμ΄μ μ μν JavaScript λͺ¨λ μ€κ³μμ 리μ€μ½ν μΉν μμΉ(LSP)μ μ΄ν΄λ³΄μΈμ. νμ νΈνμ±, μμ, λ€νμ±μ λν΄ μμ보μΈμ.
JavaScript λͺ¨λ 리μ€μ½ν μΉν μμΉ: νμ νΈνμ±
리μ€μ½ν μΉν μμΉ(LSP)μ κ°μ²΄ μ§ν₯ νλ‘κ·Έλλ°μ 5κ°μ§ SOLID μμΉ μ€ νλμ λλ€. μ΄ μμΉμ νλ‘κ·Έλ¨μ μ νμ±μ λ³κ²½νμ§ μκ³ λ μλΈνμ μ κΈ°λ³Έ νμ μΌλ‘ λ체ν μ μμ΄μΌ νλ€κ³ λͺ μν©λλ€. JavaScript λͺ¨λμ λ§₯λ½μμ μ΄λ λͺ¨λμ΄ νΉμ μΈν°νμ΄μ€ λλ κΈ°λ³Έ λͺ¨λμ μμ‘΄νλ κ²½μ°, ν΄λΉ μΈν°νμ΄μ€λ₯Ό ꡬννκ±°λ ν΄λΉ κΈ°λ³Έ λͺ¨λμμ μμλ°λ λͺ¨λ λͺ¨λμ μκΈ°μΉ μμ λμμ μΌμΌν€μ§ μκ³ ν΄λΉ μμΉμμ μ¬μ©λ μ μμ΄μΌ ν¨μ μλ―Έν©λλ€. LSPλ₯Ό μ€μνλ©΄ λμ± μ μ§λ³΄μκ° μ©μ΄νκ³ κ²¬κ³ νλ©° ν μ€νΈ κ°λ₯ν μ½λλ² μ΄μ€λ₯Ό μ»μ μ μμ΅λλ€.
리μ€μ½ν μΉν μμΉ(LSP) μ΄ν΄
LSPλ Barbara Liskovμ μ΄λ¦μ λ°μ λͺ λͺ λμμΌλ©°, κ·Έλ λ 1987λ κΈ°μ‘° μ°μ€ "Data Abstraction and Hierarchy"μμ μ΄ κ°λ μ μκ°νμ΅λλ€. μλ κ°μ²΄ μ§ν₯ ν΄λμ€ κ³μΈ΅ ꡬ쑰μ λ§₯λ½μμ 곡μνλμμ§λ§, μ΄ μμΉμ νΉν λͺ¨λ κ΅¬μ± λ° μ’ μμ± μ£Όμ μ κ³ λ €ν λ JavaScriptμ λͺ¨λ μ€κ³μλ κ΄λ ¨μ΄ μμ΅λλ€.
LSPμ ν΅μ¬ μμ΄λμ΄λ νμ νΈνμ±μ λλ€. μλΈνμ (λλ λ체 λͺ¨λ)μ κΈ°λ³Έ νμ (λλ μλ λͺ¨λ)κ³Ό λμΌν λ©μλ λλ μμ±μ λ¨μν ꡬνν΄μλ μ λ©λλ€. λν κΈ°λ³Έ νμ μ κΈ°λμ μΌκ΄λ λ°©μμΌλ‘ λμν΄μΌ ν©λλ€. μ¦, ν΄λΌμ΄μΈνΈ μ½λμμ μΈμλλ λ체 λͺ¨λμ λμμ κΈ°λ³Έ νμ μ μν΄ μ€μ λ κ³μ½μ μλ°ν΄μλ μ λ©λλ€.
곡μ μ μ
곡μμ μΌλ‘ LSPλ λ€μκ³Ό κ°μ΄ λͺ μν μ μμ΅λλ€.
Ο(x)λ₯Ό νμ Tμ κ°μ²΄ xμ λν΄ μ¦λͺ κ°λ₯ν μμ±μ΄λΌκ³ ν©μλ€. κ·Έλ¬λ©΄ Sκ° Tμ μλΈνμ μΈ κ²½μ° Ο(y)λ νμ Sμ κ°μ²΄ yμ λν΄ μ°Έμ΄μ΄μΌ ν©λλ€.
λ κ°λ¨ν λ§ν΄μ, κΈ°λ³Έ νμ μ΄ λμνλ λ°©μμ λν΄ λ¨μΈν μ μλ€λ©΄ ν΄λΉ λ¨μΈμ ν΄λΉ μλΈνμ μ λν΄μλ μ¬μ ν μ ν¨ν΄μΌ ν©λλ€.
JavaScript λͺ¨λμ LSP
JavaScriptμ λͺ¨λ μμ€ν , νΉν ES λͺ¨λ(ESM)μ LSP μμΉμ μ μ©νκΈ° μν νλ₯ν κΈ°λ°μ μ 곡ν©λλ€. λͺ¨λμ μΈν°νμ΄μ€ λλ μΆμμ λμμ λ΄λ³΄λ΄κ³ λ€λ₯Έ λͺ¨λμ μ΄λ¬ν μΈν°νμ΄μ€λ₯Ό κ°μ Έμ νμ©ν μ μμ΅λλ€. ν λͺ¨λμ λ€λ₯Έ λͺ¨λλ‘ λ체ν λ νμ νΈνμ±μ νμΈνλ κ²μ΄ μ€μν©λλ€.
μμ : μλ¦Ό λͺ¨λ
κ°λ¨ν μμ μΈ μλ¦Ό λͺ¨λμ κ³ λ €ν΄ λ³΄κ² μ΅λλ€. κΈ°λ³Έ `Notifier` λͺ¨λλΆν° μμνκ² μ΅λλ€.
// notifier.js
export class Notifier {
constructor(config) {
this.config = config;
}
sendNotification(message, recipient) {
throw new Error("sendNotification must be implemented in a subclass");
}
}
μ΄μ λ κ°μ μλΈνμ μΈ `EmailNotifier`μ `SMSNotifier`λ₯Ό λ§λ€μ΄ λ³΄κ² μ΅λλ€.
// email-notifier.js
import { Notifier } from './notifier.js';
export class EmailNotifier extends Notifier {
constructor(config) {
super(config);
if (!config.smtpServer || !config.emailFrom) {
throw new Error("EmailNotifier requires smtpServer and emailFrom in config");
}
}
sendNotification(message, recipient) {
// Send email logic here
console.log(`Sending email to ${recipient}: ${message}`);
return `Email sent to ${recipient}`; // Simulate success
}
}
// sms-notifier.js
import { Notifier } from './notifier.js';
export class SMSNotifier extends Notifier {
constructor(config) {
super(config);
if (!config.twilioAccountSid || !config.twilioAuthToken || !config.twilioPhoneNumber) {
throw new Error("SMSNotifier requires twilioAccountSid, twilioAuthToken, and twilioPhoneNumber in config");
}
}
sendNotification(message, recipient) {
// Send SMS logic here
console.log(`Sending SMS to ${recipient}: ${message}`);
return `SMS sent to ${recipient}`; // Simulate success
}
}
λ§μ§λ§μΌλ‘ `Notifier`λ₯Ό μ¬μ©νλ λͺ¨λμ λλ€.
// notification-service.js
import { Notifier } from './notifier.js';
export class NotificationService {
constructor(notifier) {
if (!(notifier instanceof Notifier)) {
throw new Error("Notifier must be an instance of Notifier");
}
this.notifier = notifier;
}
send(message, recipient) {
return this.notifier.sendNotification(message, recipient);
}
}
μ΄ μμμ `EmailNotifier`μ `SMSNotifier`λ `Notifier`λ‘ λ체 κ°λ₯ν©λλ€. `NotificationService`λ `Notifier` μΈμ€ν΄μ€λ₯Ό κΈ°λνκ³ ν΄λΉ `sendNotification` λ©μλλ₯Ό νΈμΆν©λλ€. `EmailNotifier`μ `SMSNotifier`λ λͺ¨λ μ΄ λ©μλλ₯Ό ꡬννκ³ κ΅¬νμ λ€λ₯΄μ§λ§ μλ¦Όμ 보λ΄λ κ³μ½μ μ΄νν©λλ€. μ±κ³΅μ λνλ΄λ λ¬Έμμ΄μ λ°νν©λλ€. κ²°μ μ μΌλ‘ μλ¦Όμ 보λ΄μ§ μκ±°λ μκΈ°μΉ μμ μ€λ₯λ₯Ό λ°μμν€λ `sendNotification` λ©μλλ₯Ό μΆκ°νλ©΄ LSPλ₯Ό μλ°νκ² λ©λλ€.
LSP μλ°
κ²°ν¨μ΄ μλ `SilentNotifier`λ₯Ό λμ νλ μλ리μ€λ₯Ό κ³ λ €ν΄ λ³΄κ² μ΅λλ€.
// silent-notifier.js
import { Notifier } from './notifier.js';
export class SilentNotifier extends Notifier {
sendNotification(message, recipient) {
// Does nothing! Intentionally silent.
console.log("Notification suppressed.");
return null; // Or maybe even throws an error!
}
}
`NotificationService`μμ `Notifier`λ₯Ό `SilentNotifier`λ‘ λ°κΎΈλ©΄ μ ν리μΌμ΄μ μ λμμ΄ μκΈ°μΉ μμ λ°©μμΌλ‘ λ³κ²½λ©λλ€. μ¬μ©μλ μλ¦Όμ΄ μ μ‘λ κ²μΌλ‘ μμν μ μμ§λ§ μ무 μΌλ μΌμ΄λμ§ μμ΅λλ€. λν `null` λ°ν κ°μ νΈμΆ μ½λκ° λ¬Έμμ΄μ μμνλ λ¬Έμ λ₯Ό μΌμΌν¬ μ μμ΅λλ€. μ΄λ μλΈνμ μ΄ κΈ°λ³Έ νμ κ³Ό μΌκ΄λκ² λμνμ§ μκΈ° λλ¬Έμ LSPλ₯Ό μλ°ν©λλ€. `NotificationService`λ μ΄μ `SilentNotifier`λ₯Ό μ¬μ©ν λ μμλ©λλ€.
LSP μ€μμ μ΄μ
- μ½λ μ¬μ¬μ©μ± μ¦κ°: LSPλ μ¬μ¬μ© κ°λ₯ν λͺ¨λ μμ±μ μ΄μ§ν©λλ€. μλΈνμ μ κΈ°λ³Έ νμ μΌλ‘ λ체 κ°λ₯νλ―λ‘ κΈ°μ‘΄ μ½λλ₯Ό μμ νμ§ μκ³ λ λ€μν 컨ν μ€νΈμμ μ¬μ©ν μ μμ΅λλ€.
- μ μ§λ³΄μμ± ν₯μ: μλΈνμ μ΄ LSPλ₯Ό μ€μνλ©΄ μλΈνμ μ λ³κ²½ μ¬νμΌλ‘ μΈν΄ μ ν리μΌμ΄μ μ λ€λ₯Έ λΆλΆμμ λ²κ·Έλ μκΈ°μΉ μμ λμμ΄ λ°μν κ°λ₯μ±μ΄ μ€μ΄λλλ€. μ΄λ₯Ό ν΅ν΄ μ½λλ₯Ό μ μ§λ³΄μνκ³ μκ°μ΄ μ§λ¨μ λ°λΌ λ°μ μν€κΈ° μ¬μμ§λλ€.
- ν μ€νΈ μ©μ΄μ± ν₯μ: μλΈνμ μ κΈ°λ³Έ νμ κ³Ό λ 립μ μΌλ‘ ν μ€νΈν μ μκΈ° λλ¬Έμ LSPλ ν μ€νΈλ₯Ό λ¨μνν©λλ€. κΈ°λ³Έ νμ μ λμμ νμΈνλ ν μ€νΈλ₯Ό μμ±ν λ€μ ν΄λΉ ν μ€νΈλ₯Ό μλΈνμ μ μ¬μ¬μ©ν μ μμ΅λλ€.
- κ²°ν©λ κ°μ: LSPλ λͺ¨λμ΄ κ΅¬μ²΄μ μΈ κ΅¬νμ΄ μλ μΆμμ μΈν°νμ΄μ€λ₯Ό ν΅ν΄ μνΈ μμ©ν μ μλλ‘ νμ¬ λͺ¨λ κ°μ κ²°ν©λλ₯Ό μ€μ λλ€. μ΄λ₯Ό ν΅ν΄ μ½λλ₯Ό λ μ μ°νκ² λ§λ€κ³ λ³κ²½νκΈ° μ½κ² λ§λλλ€.
JavaScript λͺ¨λμμ LSPλ₯Ό μ μ©νκΈ° μν μ€μ©μ μΈ μ§μΉ¨
- κ³μ½μ μν μ€κ³: λͺ¨λμ μμ λμμ μ§μ νλ λͺ νν κ³μ½(μΈν°νμ΄μ€ λλ μΆμ ν΄λμ€)μ μ μν©λλ€. μλΈνμ μ μ΄λ¬ν κ³μ½μ μ격νκ² μ€μν΄μΌ ν©λλ€. TypeScriptμ κ°μ λꡬλ₯Ό μ¬μ©νμ¬ μ»΄νμΌ μκ°μ μ΄λ¬ν κ³μ½μ μ μ©ν©λλ€.
- μ¬μ 쑰건 κ°ν λ°©μ§: μλΈνμ μ κΈ°λ³Έ νμ λ³΄λ€ λ μ격ν μ¬μ 쑰건μ μꡬν΄μλ μ λ©λλ€. κΈ°λ³Έ νμ μ΄ νΉμ λ²μμ μ λ ₯μ νμ©νλ κ²½μ° μλΈνμ μ λμΌν λ²μ λλ λ λμ λ²μλ₯Ό νμ©ν΄μΌ ν©λλ€.
- μ¬ν 쑰건 μ½ν λ°©μ§: μλΈνμ μ κΈ°λ³Έ νμ λ³΄λ€ λ μ½ν μ¬ν 쑰건μ 보μ₯ν΄μλ μ λ©λλ€. κΈ°λ³Έ νμ μ΄ νΉμ κ²°κ³Όλ₯Ό 보μ₯νλ κ²½μ° μλΈνμ μ λμΌν κ²°κ³Ό λλ λ κ°λ ₯ν κ²°κ³Όλ₯Ό 보μ₯ν΄μΌ ν©λλ€.
- μκΈ°μΉ μμ μμΈ λ°μ λ°©μ§: μλΈνμ μ κΈ°λ³Έ νμ μ΄ λ°μμν€μ§ μλ μμΈλ₯Ό λ°μμμΌμλ μ λ©λλ€(ν΄λΉ μμΈκ° κΈ°λ³Έ νμ μμ λ°μν μμΈμ μλΈνμ μΈ κ²½μ°λ μ μΈ).
- μμ νλͺ νκ² μ¬μ©: JavaScriptμμλ νλ‘ν νμ μμ λλ ν΄λμ€ κΈ°λ° μμμ ν΅ν΄ μμμ λ¬μ±ν μ μμ΅λλ€. κ³Όλν κ²°ν© λ° κΉ¨μ§κΈ° μ¬μ΄ κΈ°λ³Έ ν΄λμ€ λ¬Έμ μ κ°μ μμμ μ μ¬μ μΈ ν¨μ μ μ μνμμμ€. μ μ ν κ²½μ° μμλ³΄λ€ κ΅¬μ±μ μ¬μ©νλ κ²μ κ³ λ €νμμμ€.
- μΈν°νμ΄μ€ μ¬μ© κ³ λ €(TypeScript): TypeScript μΈν°νμ΄μ€λ₯Ό μ¬μ©νμ¬ κ°μ²΄μ λͺ¨μμ μ μνκ³ μλΈνμ μ΄ νμν λ©μλμ μμ±μ ꡬννλλ‘ κ°μ ν μ μμ΅λλ€. μ΄λ μλΈνμ μ κΈ°λ³Έ νμ μΌλ‘ λ체ν μ μλλ‘ νλ λ° λμμ΄ λ μ μμ΅λλ€.
κ³ κΈ κ³ λ € μ¬ν
κ°λ³μ±
κ°λ³μ±μ ν¨μμ λ§€κ°λ³μ λ° λ°ν κ°μ νμ μ΄ μΉν κ°λ₯μ±μ λ―ΈμΉλ μν₯μ λνλ λλ€. μΈ κ°μ§ μ νμ κ°λ³μ±μ΄ μμ΅λλ€.
- 곡λ³μ±: μλΈνμ μ΄ κΈ°λ³Έ νμ λ³΄λ€ λ ꡬ체μ μΈ νμ μ λ°ννλλ‘ νμ©ν©λλ€.
- λ°κ³΅λ³μ±: μλΈνμ μ΄ κΈ°λ³Έ νμ λ³΄λ€ λ μΌλ°μ μΈ νμ μ λ§€κ°λ³μλ‘ νμ©νλλ‘ νμ©ν©λλ€.
- λΆλ³μ±: μλΈνμ μ΄ κΈ°λ³Έ νμ κ³Ό λμΌν λ§€κ°λ³μ λ° λ°ν νμ μ κ°λλ‘ μꡬν©λλ€.
JavaScriptμ λμ νμ΄νμ κ°λ³μ± κ·μΉμ μ격νκ² μ μ©νλ λ° μ΄λ €μμ κ²ͺμ΅λλ€. κ·Έλ¬λ TypeScriptλ κ°λ³μ±μ λ³΄λ€ μ μ΄λ λ°©μμΌλ‘ κ΄λ¦¬νλ λ° λμμ΄ λλ κΈ°λ₯μ μ 곡ν©λλ€. ν΅μ¬μ νμ μ΄ μ λ¬Ένλ κ²½μ°μλ ν¨μ μλͺ μ΄ νΈνμ±μ μ μ§νλλ‘ νλ κ²μ λλ€.
λͺ¨λ κ΅¬μ± λ° μ’ μμ± μ£Όμ
LSPλ λͺ¨λ κ΅¬μ± λ° μ’ μμ± μ£Όμ κ³Ό λ°μ ν κ΄λ ¨μ΄ μμ΅λλ€. λͺ¨λμ ꡬμ±ν λ λͺ¨λμ΄ λμ¨νκ² κ²°ν©λμ΄ μκ³ μΆμμ μΈν°νμ΄μ€λ₯Ό ν΅ν΄ μνΈ μμ©νλμ§ νμΈνλ κ²μ΄ μ€μν©λλ€. μ’ μμ± μ£Όμ μ μ¬μ©νλ©΄ λ°νμμ μΈν°νμ΄μ€μ λ€λ₯Έ ꡬνμ μ£Όμ ν μ μμΌλ©° μ΄λ ν μ€νΈ λ° κ΅¬μ±μ μ μ©ν μ μμ΅λλ€. LSP μμΉμ μ΄λ¬ν λμ²΄κ° μμ νκ³ μκΈ°μΉ μμ λμμ μΌμΌν€μ§ μλλ‘ νλ λ° λμμ΄ λ©λλ€.
μ€μ μμ : λ°μ΄ν° μ‘μΈμ€ λ μ΄μ΄
λ€λ₯Έ λ°μ΄ν° μμ€μ λν μ‘μΈμ€λ₯Ό μ 곡νλ λ°μ΄ν° μ‘μΈμ€ λ μ΄μ΄(DAL)λ₯Ό κ³ λ €ν΄ λ³΄κ² μ΅λλ€. `MySQLDataAccess`, `PostgreSQLDataAccess` λ° `MongoDBDataAccess`μ κ°μ μλΈνμ μ΄ μλ κΈ°λ³Έ `DataAccess` λͺ¨λμ΄ μμ μ μμ΅λλ€. κ° μλΈνμ μ λμΌν λ©μλ(μ: `getData`, `insertData`, `updateData`, `deleteData`)λ₯Ό ꡬννμ§λ§ λ€λ₯Έ λ°μ΄ν°λ² μ΄μ€μ μ°κ²°ν©λλ€. LSPλ₯Ό μ€μνλ©΄ ν΄λΉ λͺ¨λμ μ¬μ©νλ μ½λλ₯Ό λ³κ²½νμ§ μκ³ λ μ΄λ¬ν λ°μ΄ν° μ‘μΈμ€ λͺ¨λ κ°μ μ νν μ μμ΅λλ€. ν΄λΌμ΄μΈνΈ μ½λλ `DataAccess` λͺ¨λμμ μ 곡νλ μΆμμ μΈν°νμ΄μ€μλ§ μμ‘΄ν©λλ€.
κ·Έλ¬λ MongoDBμ νΉμ±μ `MongoDBDataAccess` λͺ¨λμ΄ νΈλμμ μ μ§μνμ§ μκ³ λ€λ₯Έ λ°μ΄ν° μ‘μΈμ€ λͺ¨λμ΄ νΈλμμ μ μ§μνλ λμ `beginTransaction`μ΄ νΈμΆλ λ μ€λ₯λ₯Ό λ°μμν¨λ€κ³ μμν΄ λ³΄μμμ€. μ΄λ `MongoDBDataAccess`λ₯Ό μμ ν λ체ν μ μκΈ° λλ¬Έμ LSPλ₯Ό μλ°ν©λλ€. μ μ¬μ μΈ ν΄κ²°μ± μ `MongoDBDataAccess`μ λν΄ μ무κ²λ μννμ§ μλ `NoOpTransaction`μ μ 곡νμ¬ μμ μμ²΄κ° μ무 μμ μ΄ μλλλΌλ μΈν°νμ΄μ€λ₯Ό μ μ§νλ κ²μ λλ€.
κ²°λ‘
리μ€μ½ν μΉν μμΉμ JavaScript λͺ¨λ μ€κ³μ λ§€μ° κ΄λ ¨μ΄ μλ κ°μ²΄ μ§ν₯ νλ‘κ·Έλλ°μ κΈ°λ³Έ μμΉμ λλ€. LSPλ₯Ό μ€μνλ©΄ λμ± μ¬μ¬μ© κ°λ₯νκ³ μ μ§λ³΄μ κ°λ₯νλ©° ν μ€νΈ κ°λ₯ν λͺ¨λμ λ§λ€ μ μμ΅λλ€. μ΄λ μκ°μ΄ μ§λ¨μ λ°λΌ μ§ννκΈ° μ¬μ΄ λ³΄λ€ κ°λ ₯νκ³ μ μ°ν μ½λλ² μ΄μ€λ‘ μ΄μ΄μ§λλ€.
ν΅μ¬μ νμ νΈνμ±μ΄λΌλ κ²μ κΈ°μ΅νμμμ€. μλΈνμ μ κΈ°λ³Έ νμ μ κΈ°λμ μΌκ΄λ λ°©μμΌλ‘ λμν΄μΌ ν©λλ€. λͺ¨λμ μ μ€νκ² μ€κ³νκ³ λ체 κ°λ₯μ±μ κ³ λ €ν¨μΌλ‘μ¨ LSPμ μ΄μ μ μ»κ³ JavaScript μ ν리μΌμ΄μ μ μν λ³΄λ€ κ²¬κ³ ν κΈ°λ°μ λ§λ€ μ μμ΅λλ€.
리μ€μ½ν μΉν μμΉμ μ΄ν΄νκ³ μ μ©ν¨μΌλ‘μ¨ μ μΈκ³μ κ°λ°μλ μ΅μ μννΈμ¨μ΄ κ°λ°μ κ³Όμ λ₯Ό μΆ©μ‘±νλ λ³΄λ€ μμ μ μ΄κ³ μ μ κ°λ₯ν JavaScript μ ν리μΌμ΄μ μ ꡬμΆν μ μμ΅λλ€. λ¨μΌ νμ΄μ§ μ ν리μΌμ΄μ μμ 볡μ‘ν μλ² μΈ‘ μμ€ν μ μ΄λ₯΄κΈ°κΉμ§ LSPλ μ μ§λ³΄μκ° μ©μ΄νκ³ κ°λ ₯ν μ½λλ₯Ό λ§λλ λ° μ μ©ν λꡬμ λλ€.